package com.sudo.api._admin;

import com.sudo.common.annotation.ApiIdempotent;
import com.sudo.common.annotation.ApiAuthorization;
import com.sudo.common.enums.SysJobStatus;
import com.sudo.common.task.BaseTaskRegistry;
import com.sudo.common.task.TaskMethod;
import com.sudo.common.task.TaskUtil;
import com.sudo.common.utils.*;
import com.sudo.dao.admin.entity.SysMethodJob;
import com.sudo.dao.admin.model.bo.SysMethodJobBO;
import com.sudo.dao.admin.model.bo.SysRunMethodJobBO;
import com.sudo.service.admin.service.SysMethodJobService;
import com.sudo.service.tldata.ThreadLocalObject;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.scheduling.support.CronExpression;
import org.springframework.validation.BindingResult;
import org.springframework.web.bind.annotation.*;

import javax.annotation.Resource;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.validation.Valid;
import java.lang.reflect.Method;
import java.util.Map;

@Slf4j
@Api(value = "方法定时任务接口",tags = {"方法定时任务管理相关的接口"})
@RestController
@RequestMapping("sysMethodJob")
public class SysMethodJobController extends AdminBaseController{

    @Resource
    private SysMethodJobService sysMethodJobService;

    @ApiOperation(value = "获取调度模块列表",notes = "获取调度模块列表",httpMethod = "GET")
    @GetMapping("/getTaskModuleMap")
    public JsonRes getTaskModuleList() {
        Map<String,String> taskModuleList = sysMethodJobService.getTaskModuleMap();
        return JsonRes.ok(taskModuleList);
    }

    @ApiOperation(value = "分页查询方法定时任务",notes = "分页查询方法定时任务",httpMethod = "POST")
    @PostMapping("/querySysMethodJobByPage")
    public JsonRes querySysMethodJobByPage(@RequestBody SysMethodJobBO sysMethodJobBO) {
        PagedGridResult pagedGridResult = sysMethodJobService.querySysMethodJobByPage(sysMethodJobBO);
        return JsonRes.ok(pagedGridResult);
    }

    @ApiAuthorization(menu = "method_job",button = "detail")
    @ApiOperation(value = "查询定时任务",notes = "查询定时任务",httpMethod = "GET")
    @GetMapping("/querySysMethodJobById")
    public JsonRes querySysMethodJobById(@RequestParam(value = "id",required = true)Integer id) {
        SysMethodJob sysMethodJob = sysMethodJobService.querySysMethodJobById(id);
        return JsonRes.ok(sysMethodJob);
    }

    @ApiOperation(value = "获取方法参数文档",notes = "获取方法参数文档",httpMethod = "GET")
    @GetMapping("/getMethodDocumentMap")
    public JsonRes getMethodDocumentMap() {
        Map<String, Map<String,TaskMethod>> taskMethodMap = sysMethodJobService.getMethodAndParamCountList();
        return JsonRes.ok(taskMethodMap);
    }

    @ApiIdempotent
    @ApiAuthorization(menu = "method_job",button = "add")
    @ApiOperation(value = "创建方法任务",notes = "创建方法任务",httpMethod = "POST")
    @PostMapping("/saveSysMethodJob")
    public JsonRes saveSysMethodJob(@RequestBody @Valid SysMethodJobBO sysMethodJobBO,
                                    BindingResult result,
                                    HttpServletRequest request) {
        if (result.hasErrors()) {
            return JsonRes.errorMsg(getFirstError(result));
        }
        boolean validExpression = CronExpression.isValidExpression(sysMethodJobBO.getCronExpression());
        if (!validExpression) {
            return JsonRes.errorMsg("cron表达式不正确");
        }
        try {
            Class<?> aClass = BaseTaskRegistry.getClassByBean(sysMethodJobBO.getBeanName());
            if (StringUtils.isBlank(sysMethodJobBO.getMethodParams())) {
                Method declaredMethod = aClass.getDeclaredMethod(sysMethodJobBO.getMethodName());
                if (declaredMethod == null){
                    return JsonRes.errorMsg("不存在该 "+ sysMethodJobBO.getMethodName() +"() 类型的方法");
                }
            }else {
                Method declaredMethod = aClass.getDeclaredMethod(sysMethodJobBO.getMethodName(),Map.class);
                if (declaredMethod == null){
                    return JsonRes.errorMsg("不存在该 "+ sysMethodJobBO.getMethodName() +"(Map map) 类型的方法");
                }else {
                    Map<String,Object> paramMap = JsonUtil.jsonToPojo(sysMethodJobBO.getMethodParams(), Map.class);
                    if (null == paramMap) {
                        return JsonRes.errorMsg("参数格式异常，请保持Json对象格式");
                    }
                    boolean paramStatus = TaskUtil.verifyParam(sysMethodJobBO.getBeanName(),sysMethodJobBO.getMethodName(),paramMap);
                    if (!paramStatus){
                        return JsonRes.errorMsg("参数格式异常，请严格遵从参数类型、是否必填");
                    }
                }
            }
        } catch (NoSuchMethodException e) {
            log.error("获取方法异常：",e);
            if (StringUtils.isBlank(sysMethodJobBO.getMethodParams())) {
                return JsonRes.errorMsg("不存在该 "+ sysMethodJobBO.getMethodName() +"() 类型的方法");
            }else {
                return JsonRes.errorMsg("不存在该 "+ sysMethodJobBO.getMethodName() +"(Map map) 类型的方法");
            }
        }
        String sessionUser = HttpUserInfoUtil.getSessionUser(request);
        int affectCount = sysMethodJobService.saveSysMethodJob(sysMethodJobBO, sessionUser);
        return JsonRes.judge(affectCount, "新增成功", "新增失败");
    }

    @ApiIdempotent
    @ApiAuthorization(menu = "method_job",button = "update")
    @ApiOperation(value = "修改定时任务状态",notes = "修改定时任务状态",httpMethod = "POST")
    @PostMapping("/updateSysMethodJobStatus")
    public JsonRes updateSysMethodJobStatus(@RequestBody SysMethodJobBO sysMethodJobBO) {
        int affectCount = sysMethodJobService.updateSysMethodJobStatus(sysMethodJobBO);
        return JsonRes.judge(affectCount, "修改成功", "修改失败");
    }

    @ApiIdempotent
    @ApiAuthorization(menu = "method_job",button = "update")
    @ApiOperation(value = "编辑定时任务（不包括状态）",notes = "编辑定时任务（不包括状态）",httpMethod = "POST")
    @PostMapping("/updateSysMethodJobWithNoStatus")
    public JsonRes updateSysMethodJobWithNoStatus(@RequestBody @Valid SysMethodJobBO sysMethodJobBO,
                                                  BindingResult result) {
        SysMethodJob sysMethodJob = sysMethodJobService.querySysMethodJobById(sysMethodJobBO.getId());
        if (SysJobStatus.RUN.name().equals(sysMethodJob.getStatus())) {
            return JsonRes.errorMsg("修改任务前必须停止该任务");
        }
        if (result.hasErrors()) {
            return JsonRes.errorMsg(getFirstError(result));
        }
        boolean validExpression = CronExpression.isValidExpression(sysMethodJobBO.getCronExpression());
        if (!validExpression) {
            return JsonRes.errorMsg("cron表达式不正确");
        }
        try {
            Class<?> aClass = BaseTaskRegistry.getClassByBean(sysMethodJob.getBeanName());
            if (StringUtils.isBlank(sysMethodJobBO.getMethodParams())) {
                Method declaredMethod = aClass.getDeclaredMethod(sysMethodJobBO.getMethodName());
                if (declaredMethod == null){
                    return JsonRes.errorMsg("不存在该 "+ sysMethodJobBO.getMethodName() +"() 类型的方法");
                }
            }else {
                Method declaredMethod = aClass.getDeclaredMethod(sysMethodJobBO.getMethodName(),Map.class);
                if (declaredMethod == null){
                    return JsonRes.errorMsg("不存在该 "+ sysMethodJobBO.getMethodName() +"(Map map) 类型的方法");
                }else {
                    Map<String,Object> paramMap = JsonUtil.jsonToPojo(sysMethodJobBO.getMethodParams(), Map.class);
                    if (null == paramMap) {
                        return JsonRes.errorMsg("参数格式异常，请保持Json对象格式");
                    }
                    boolean paramStatus = TaskUtil.verifyParam(sysMethodJobBO.getBeanName(),sysMethodJobBO.getMethodName(),paramMap);
                    if (!paramStatus){
                        return JsonRes.errorMsg("参数格式异常，请严格遵从参数类型、是否必填");
                    }
                }
            }
        } catch (NoSuchMethodException e) {
            log.error("获取方法异常：",e);
            if (StringUtils.isBlank(sysMethodJobBO.getMethodParams())) {
                return JsonRes.errorMsg("不存在该 "+ sysMethodJobBO.getMethodName() +"() 类型的方法");
            }else {
                return JsonRes.errorMsg("不存在该 "+ sysMethodJobBO.getMethodName() +"(Map map) 类型的方法");
            }
        }
        int affectCount = sysMethodJobService.updateSysMethodJobWithNoStatus(sysMethodJobBO);
        return JsonRes.judge(affectCount, "修改成功", "修改失败");
    }

    @ApiIdempotent
    @ApiAuthorization(menu = "method_job",button = "delete")
    @ApiOperation(value = "删除定时任务",notes = "删除定时任务",httpMethod = "POST")
    @PostMapping("/deleteSysMethodJob")
    public JsonRes deleteSysMethodJob(@RequestParam Integer id) {
        SysMethodJob sysMethodJob = sysMethodJobService.querySysMethodJobById(id);
        if (SysJobStatus.RUN.name().equals(sysMethodJob.getStatus())) {
            return JsonRes.errorMsg("删除任务前必须停止该任务");
        }
        int affectCount = sysMethodJobService.deleteSysMethodJob(id);
        return JsonRes.judge(affectCount, "删除成功", "删除失败");
    }

    @ApiIdempotent
    @ApiAuthorization(menu = "method_job", button = "run")
    @ApiOperation(value = "运行一次任务", notes = "运行一次任务", httpMethod = "POST")
    @PostMapping("/runSysMethodJob")
    public void runSysMethodJob(HttpServletResponse response,
                                @RequestBody SysRunMethodJobBO runMethodJobBO) throws Exception {
        SysMethodJob sysMethodJob = sysMethodJobService.querySysMethodJobById(runMethodJobBO.getId());

        JsonRes jsonRes = JsonRes.errorMsg("");
        Class<?> aClass = BaseTaskRegistry.getClassByBean(sysMethodJob.getBeanName());
        if (StringUtils.isBlank(runMethodJobBO.getMethodParams())) {
            Method declaredMethod = aClass.getDeclaredMethod(sysMethodJob.getMethodName());
            if (declaredMethod == null){
                jsonRes.setMsg("不存在该 "+ sysMethodJob.getMethodName() +"() 类型的方法");
                RetResponse.res(response,jsonRes);
                return;
            }
        }else {
            Method declaredMethod = aClass.getDeclaredMethod(sysMethodJob.getMethodName(),Map.class);
            if (declaredMethod == null){
                jsonRes.setMsg("不存在该 "+ sysMethodJob.getMethodName() +"(Map map) 类型的方法");
                RetResponse.res(response,jsonRes);
                return;
            }else {
                Map<String,Object> paramMap = JsonUtil.jsonToPojo(runMethodJobBO.getMethodParams(), Map.class);
                if (null == paramMap) {
                    jsonRes.setMsg("参数格式异常，请保持Json对象格式");
                    RetResponse.res(response,jsonRes);
                    return;
                }
                boolean paramStatus = TaskUtil.verifyParam(sysMethodJob.getBeanName(),sysMethodJob.getMethodName(),paramMap);
                if (!paramStatus){
                    jsonRes.setMsg("参数格式异常，请严格遵从参数类型、是否必填");
                    RetResponse.res(response,jsonRes);
                    return;
                }
            }
        }
        sysMethodJob.setMethodParams(runMethodJobBO.getMethodParams());
        Map<String, Object> jobConfigMap = ThreadLocalObject.initJobConfigMap(sysMethodJob);
        ThreadLocalUtil.setTlMap(jobConfigMap);
        TaskUtil.callTaskMethod(sysMethodJob.getBeanName(),sysMethodJob.getMethodName(),sysMethodJob.getMethodParams());
    }

}
